home *** CD-ROM | disk | FTP | other *** search
- /*
- * AppleTalk / Ethernet Gateway; part 2.
- *
- * (c) 1986, Stanford Univ. CSLI.
- * May be used but not sold without permission.
- *
- * $Header: gw2.c,v 4.1 88/11/01 19:49:25 sw0l Locked $
- */
-
- #include "gw.h"
- #include "gwctl.h"
- #include "fp/pbuf.h"
- #include "ab.h"
- #include "inet.h"
- #include "fp/cmdmacro.h"
- #ifdef SNMP
- #include "snmp.h"
- #include "mib.h"
- #include "snmp_vars.h"
- #endif
-
- #include "glob.h"
-
- /*
- * NBP packet input from appletalk (abreceive).
- */
- nbpinput(p)
- struct pbuf *p;
- {
- register struct NBP *n = (struct NBP *)(p->p_off + lapSize + ddpSize);
- register op = (n->control & nbpControlMask);
- Entity ent;
- register iaddr;
-
- /*
- * if bridge request, put on backround queue
- * to nbpback, who will send all the LkUp's.
- */
- if (op == nbpBrRq) {
- K_PENQNP(&nbpq, p);
- return;
- }
- /* else packet is a LkUp or LkUpReply, check for local names */
- nbpgetent(n->tuple.name, &ent); /* break up tuple name entity */
- /*
- * if lookup reply for us, complete any pending requests.
- */
- if (op == nbpLkUpReply) {
- if (ddp.dstNode != ifab.if_dnode
- || strcmp(ent.type, "IPADDRESS") != 0
- || (iaddr = atoip(ent.obj, 99)) == 0 )
- goto drop;
- /* pass the address reply to ARP and ipdad modules */
- arpgotreply(&ifab, iaddr, &n->tuple.addr);
- ipdadreply(&ifab, iaddr, &n->tuple.addr);
- goto drop;
- }
- /*
- * else lookup; handle requests for our IP related services.
- */
- if (strcmp(ent.type, "IPGATEWAY") == 0) {
- iaddr = conf.ipaddr;
- goto replyus;
- }
- if (strcmp(ent.type, "IPADDRESS") == 0) {
- if ((iaddr = atoip(ent.obj, 99)) == 0
- || ipbroadcast(iaddr))
- goto drop; /* dont reply to bad addresses */
- if (abmatch(iaddr))
- goto replyus;
- }
- if (strcmp(ent.type, "=") == 0 && strcmp(ent.obj, "=") == 0) {
- iaddr = conf.ipaddr;
- strcpy(ent.type, "IPGATEWAY");
- goto reply;
- }
- goto drop;
- replyus:
- if (getaroute(n->tuple.addr.net) == 0)
- goto drop; /* not our responsibility */
- reply:
- iptoa(iaddr, ent.obj);
- /* Should always return with "my zone" */
- ddp.length = nbpsetent(n->tuple.name, ent.obj, ent.type, "*")
- + ddpSize + nbpMinSize;
- ddp.checksum = 0;
- ddp.srcNet = source_if->if_dnet;
- ddp.srcNode = source_if->if_dnode;
- ddp.dstNet = n->tuple.addr.net;
- ddp.dstNode = n->tuple.addr.node;
- ddp.dstSkt = n->tuple.addr.skt;
- n->tuple.addr.net = ddp.srcNet;
- n->tuple.addr.node = ddp.srcNode;
- n->tuple.addr.skt = ddpIPSkt;
- ddp.srcSkt = nbpNIS;
- n->control = nbpLkUpReply + 1;
- p->p_len = ddp.length + lapSize;
- bcopy((caddr_t)&ddp, p->p_off+lapSize, ddpSize);
- routeddp(p, 0, 0);
- return;
- drop:
- K_PFREE(p);
- }
-
-
- /*
- * Queue an NBP lookup request. If net/node is non-zero,
- * does an 'nbpconfirm' operation.
- */
- nbplookup(ent, net, node)
- Entity *ent;
- {
- register struct NBP *n;
- register struct pbuf *p;
- struct DDP d;
-
- K_PGET(PT_DATA, p);
- if (p == 0)
- return;
- n = (struct NBP *)(p->p_off + lapSize + ddpSize);
- n->control = nbpLkUp + 1;
- n->id = 0;
- n->tuple.enume = 0;
- n->tuple.addr.net = d.srcNet = ifab.if_dnet;
- n->tuple.addr.node = d.srcNode = ifab.if_dnode;
- n->tuple.addr.skt = d.srcSkt = d.dstSkt = nbpNIS;
- d.checksum = 0;
- d.type = ddpNBP;
- d.length = nbpsetent(n->tuple.name, ent->obj, ent->type, ent->zone)
- + ddpSize + nbpMinSize;
- p->p_off[2] = lapDDP;
- p->p_len = d.length + lapSize;
- if (net) { /* wants an nbpconfirm */
- d.dstNet = net;
- d.dstNode = node;
- }
- bcopy((caddr_t)&d, p->p_off + lapSize, ddpSize);
- if (net) {
- bcopy((caddr_t)&d, (caddr_t)&ddp, ddpSize);
- routeddp(p, 0, 0);
- } else {
- K_PENQNP(&nbpq, p);
- }
- }
-
-
- /* 'static' */
- struct aroute *nback_arfrom;
- struct aroute *nback_arnext;
- short nback_zoneindex;
-
- /*
- * NBP 'backround'. Check nbpq for BrRq's to be sent out as LkUp's.
- * Sends to one net per call/loop.
- */
- nbpback()
- {
- register struct aroute *ar, *arx;
- register struct pbuf *pq, *p;
- struct NBP *n;
- register int zi;
- u_char i;
- u_char *zone;
-
- if ((pq = nbpq.pq_head) == 0)
- return; /* if nothing to do */
- if (sendq->pq_head)
- return; /* delay if ether sendq exists */
-
- if ((ar = nback_arnext) == 0) { /* first time for this packet */
- ar = nback_arnext = &aroute[0];
- bcopy(pq->p_off + lapSize, (caddr_t)&ddp, ddpSize);
- ddp.checksum = 0;
- ddp.dstNode = 0xFF; /* dstNet set below */
- n = (struct NBP *)(pq->p_off + lapSize + ddpSize);
- n->control = nbpLkUp + 1;
- zi = n->tuple.name[0] + 1; /* skip name */
- /* should check to see if we are off end of pkt */
- if (zi > 33)
- goto drop;
- if (n->tuple.name[zi] > 32)
- goto drop;
- zi += n->tuple.name[zi] + 1; /* skip type */
- zone = &n->tuple.name[zi]; /* zone length + zone */
- if (zone[0] > 32)
- goto drop;
- /* find route */
- for (arx = &aroute[0]; arx < &aroute[NAROUTE]; ++arx)
- if (arx->net == ddp.srcNet)
- break;
- /* forget it if we can't figure out where it came from */
- if (arx >= &aroute[NAROUTE])
- goto drop;
- /* Translate '*' to my zone */
- if (zone[0] == 1 && zone[1] == '*') {
- /* Choose the zone for the interface message came from */
- if (arx->zone == 0)
- goto drop;
- i = azone[arx->zone][0]+1;
- bcopy(azone[arx->zone], zone, i);
- i -= 2; /* -2 for '\01*' */
- pq->p_len += i;
- ddp.length += i;
- }
- nback_arfrom = arx;
- /* copy deferred from above so we can reset ddp length */
- bcopy((caddr_t)&ddp, pq->p_off + lapSize, ddpSize);
- if ((nback_zoneindex = zipfind(zone, 1)) == -1)
- goto drop;
- }
- n = (struct NBP *)(pq->p_off + lapSize + ddpSize);
- /*
- * for each net, route a packet there
- */
- for ( ; ar < &aroute[NAROUTE] ; ++ar) {
- if (ar->net == 0)
- continue;
- /* continue if wrong zone and the zone is not all zones */
- /* make sure allzones is set before using */
- if (ar->zone != nback_zoneindex &&
- !(allzones && ar->zone == allzones))
- continue;
- K_PGET(PT_DATA, p);
- if (p == 0)
- return; /* try later */
- /* copy efficiently in 4 byte (long) chunks */
- bcopy(pq->p_off, p->p_off, ((pq->p_len + 3) & 0xFFFC));
- p->p_len = pq->p_len;
- /*
- * Set the net number directly into the ddp header,
- * without copying. Setup a few ddp.xxx globals for
- * the convenience of 'routeddp'.
- */
- p->p_off[7] = (ar->net >> 8);
- p->p_off[8] = ar->net;
- ddp.srcNet = nback_arfrom->net;
- ddp.dstNet = ar->net;
- ddp.dstNode = 0xFF;
- ddp.dstSkt = ddp.srcSkt = nbpNIS;
- routeddp(p, porttoif[nback_arfrom->port], 0);
- nback_arnext = ar + 1;
- return;
- }
- drop:
- /* done with this BrRq, dequeue it */
- K_PDEQNP(&nbpq, pq);
- K_PFREE(pq);
- nback_arnext = 0;
- }
-
-
- /*
- * Ask "who has" IP address addr, using NBP on my locally
- * connected segments.
- */
- nbpwhohasip(addr)
- iaddr_t addr;
- {
- Entity ent;
-
- iptoa(addr, ent.obj);
- strcpy(ent.zone, "*");
- strcpy(ent.type, "IPADDRESS");
- nbplookup(&ent, 0, 0);
- }
-
-
- /*
- * Unpack an nbp entity starting at cp.
- * Returns total size of entity (for skipping to next tuple).
- */
- nbpgetent(cp, ent)
- register char *cp;
- register Entity *ent;
- {
- char *oldcp;
- register i;
-
- oldcp = cp;
- i = (*cp & 0x1F); bcopy(cp+1, ent->obj, i); ent->obj[i] = 0; cp += i+1;
- i = (*cp & 0x1F); bcopy(cp+1, ent->type, i); ent->type[i] = 0; cp += i+1;
- i = (*cp & 0x1F); bcopy(cp+1, ent->zone, i); ent->zone[i] = 0; cp += i+1;
- return (cp - oldcp);
- }
-
-
- /*
- * Setup an nbp entity field with object, type, and zone strings.
- * Returns length of this tuple.
- */
- nbpsetent(cp, obj, type, zone)
- register char *cp;
- char *obj, *type, *zone;
- {
- register char *oldcp = cp;
- register i;
-
- *cp = i = strlen(obj); bcopy(obj, cp+1, i); cp += i+1;
- *cp = i = strlen(type); bcopy(type, cp+1, i); cp += i+1;
- *cp = i = strlen(zone); bcopy(zone, cp+1, i); cp += i+1;
- return (cp - oldcp);
- }
-
-
- /*
- * Filter out certain NBP lookup replies to provide (some)
- * security for LaserWriter and other servers outside the local zone.
- */
- nbpfilter(p)
- struct pbuf *p;
- {
- register struct NBP *n = (struct NBP *)(p->p_off + lapSize + ddpSize);
- register u_char *cp;
- register i,j;
- register struct aroute *ar;
- char filter = 0;
-
- if ((n->control & nbpControlMask) != nbpLkUpReply)
- return (0);
- cp = n->tuple.name;
- if (conf.flags & conf_tildefilter) {
- i = *cp;
- if (cp[i] == '~')
- filter++;
- }
- if(conf.flags & conf_laserfilter) {
- cp += *cp + 1;
- if (*cp == 11 && strncmpci(cp+1, "LaserWriter", 11) == 0)
- filter++;
- }
- if (filter == 0)
- return (0);
- /*
- * if srcNet is in my zone but dstNet is not,
- * drop it.
- */
- i = j = 0;
- for (ar = &aroute[0] ; ar < &aroute[NAROUTE] ; ++ar) {
- if (ar->net == ddp.srcNet)
- i = ar->zone;
- if (ar->net == ddp.dstNet)
- j = ar->zone;
- if (i && j)
- break;
- }
- if (i != aroute[0].zone)
- return (0);
- if (j == i)
- return (0);
- return (1); /* drop it */
- }
-
-
- /*
- * Process an IP packet directed to the gateway's own IP address.
- * These are usually control packets such as admin configure/
- * net table, debug packets, ICMP packets.
- */
- ip4me(p)
- struct pbuf *p;
- {
- register struct ip *ip = (struct ip *)p->p_off;
- int hlen = ip->ip_hl << 2;
- struct udp *u;
- register struct gwdb *g;
- register struct aaconf *m;
- struct icmp *ic;
-
- if (ip->ip_p == IPPROTO_ICMP)
- goto icmp;
- if (ip->ip_p == IPPROTO_UDP)
- goto udp;
- #ifdef SNMP
- mib_ip.ipInUnknownProtos++;
- #endif
- drop:
- K_PFREE(p);
- return;
- udp:
- #ifdef SNMP
- mib_ip.ipInDelivers++;
- #endif
- u = (struct udp *)(p->p_off + hlen);
- switch (u->dst) {
- case aaPort:
- #ifdef SNMP
- mib_udp.udpInDatagrams++;
- #endif
- m = (struct aaconf *)(u+1);
- /* this may be too inflexible, but so be it */
- if (m->magic != aaMagic || ipRus(ip->ip_src) == 0)
- goto drop; /* not from our friends */
- switch (m->type) {
- case aaCONF:
- confready(m);
- break;
-
- case aaROUTEI:
- azoneinit = 0; /* need to fetch zone info */
- case aaROUTE:
- case aaROUTEQ:
- artinput(m, ip->ip_src);
- break;
-
- case aaRESTART:
- K_EXECUTE();
- break;
- #ifdef notdef
- case aaZONE:
- zipinit(m);
- break;
- #endif
- case aaZONEQ:
- zipinput(m->stuff,(int)m->count, ip->ip_src);
- break;
- }
- goto drop;
-
- case gwdbPort:
- #ifdef SNMP
- mib_udp.udpInDatagrams++;
- #endif
- goto gwdb;
-
- case rebPort:
- #ifdef SNMP
- mib_udp.udpInDatagrams++;
- #endif
- if (ip->ip_dst != conf.ipaddr)
- goto drop;
- bcopy((caddr_t)(u+1) + lapSize, &ddp, ddpSize);
- p->p_off += hlen + sizeof *u;
- p->p_len -= hlen + sizeof *u;
- routeddp(p, 0, 0);
- return;
- #ifdef SNMP
- case SNMP_PORT:
- mib_udp.udpInDatagrams++;
- snmp_input(p);
- goto drop;
- default:
- mib_udp.udpNoPorts++;
- #endif SNMP
- }
- goto drop;
- gwdb:
- g = (struct gwdb *)(u+1);
- if (ip->ip_src != conf.ipdebug || g->magic != gwdbMagic)
- goto drop;
- switch (g->op) {
- case gwdbRead:
- bcopy(g->address, g->data, g->count);
- break;
-
- case gwdbWrite:
- bcopy(g->data, g->address, g->count);
- break;
-
- default:
- g->op = 0; /* error reply code */
- }
- /*
- * Assume the packet length does not change.
- */
- u->checksum = 0;
- #ifdef SNMP
- mib_udp.udpOutDatagrams++;
- #endif
- flip:
- ip->ip_dst = ip->ip_src;
- ip->ip_src = conf.ipaddr;
- ip->ip_sum = 0;
- ip->ip_sum = in_cksum((caddr_t)ip, hlen);
- routeip(p, 0, 0);
- return;
- icmp:
- #ifdef SNMP
- mib_ip.ipInDelivers++;
- mib_icmpInMsgs++;
- #endif
- ic = (struct icmp *)(p->p_off + hlen);
- #ifdef SNMP
- mib_icmpInCount[ic->icmp_type]++;
- #endif
- if (ic->icmp_type == ICMP_ECHO) {
- ic->icmp_type = ICMP_ECHOREPLY;
- ic->icmp_cksum = 0;
- ic->icmp_cksum = in_cksum((caddr_t)ic, ip->ip_len - hlen);
- #ifdef SNMP
- mib_icmpOutCount[ic->icmp_type]++;
- mib_icmpOutMsgs++;
- #endif
- goto flip;
- }
- goto drop;
- }
-
-
- /*
- * IP are us. Returns true if this IP address is 'one of us':
- * the administrator or one of the configured gateways.
- */
- ipRus(ia)
- iaddr_t ia;
- {
- register struct aroute *ar;
- register f;
-
- f = (arouteKbox|arouteAA);
- if (ia == conf.ipadmin || ia == conf.ipdebug)
- return (1);
- for (ar = &aroute[0] ; ar < &aroute[NAROUTE] ; ++ar) {
- if (ar->net == 0)
- continue;
- if ((ar->flags & f) != f)
- continue;
- if (ar->node == ia)
- return (1);
- }
- return (0);
- }
-
- /*
- * Process a DDP packet directed to the gateway's own address.
- * Called from routeddp with the ddp header already unpacked
- * in global struct 'ddp'.
- */
- ddp4me(p)
- register struct pbuf *p;
- {
- register struct ATP *a;
- register struct IPGP *ig;
-
- switch (ddp.type) {
- case ddpNBP:
- if (ddp.dstSkt != nbpNIS)
- goto drop;
- nbpinput(p);
- return;
- case ddpRTMP:
- case ddpRTMPR:
- if (ddp.dstSkt != rtmpSkt)
- goto drop;
- rtmpinput(p);
- return;
- case ddpECHO:
- if (ddp.dstSkt != echoSkt)
- goto drop;
- if (p->p_off[lapSize+ddpSize] != echoRequest)
- goto drop;
- p->p_off[lapSize+ddpSize] = echoReply;
- ddpreply(p, echoSkt);
- return;
- case ddpZIP:
- if (ddp.dstSkt == zipSkt)
- zipinput(p->p_off+lapSize+ddpSize, p->p_len-lapSize-ddpSize,0L);
- goto drop;
- case ddpATP:
- if (ddp.dstSkt == zipSkt) {
- zipatp(p);
- return;
- }
- if (ddp.dstSkt != ddpIPSkt)
- goto drop;
- break;
- default:
- goto drop;
- }
- a = (struct ATP *)(p->p_off + lapSize + ddpSize);
- if ((ddp.length & ddpLengthMask) < (ddpSize + sizeof *a + 4))
- goto drop;
- if ((a->control & (~atpFlagMask)) != atpReqCode)
- goto drop;
- ig = (struct IPGP *)(a + 1);
- switch (ig->op) {
- case ipgpAssign:
- case ipgpServer:
- ipgassign(ig, ig->op);
- break;
-
- /* case ipgpName:
- ipgname(ig);
- goto drop;*/
-
- default:
- strcpy(ig->string, "bad op");
- ig->op = -1;
- break;
- }
- a->control = atpRspCode + atpEOM;
- a->bitmap = 0;
- /* +1 is to account for null */
- p->p_len=lapSize+ddpSize+sizeof(*a)+ipgpMinSize+strlen(ig->string)+1;
- ddpreply(p, ddpIPSkt);
- return;
- drop:
- K_PFREE(p);
- }
-
-
- /*
- * IPGATEWAY request to assign address.
- */
- ipgassign(ig, op)
- register struct IPGP *ig;
- {
- register struct ipdad *d;
- struct ipdad *od;
- int dmax, otimer;
- register i;
-
- if (op == ipgpServer)
- goto server; /* skip most of this */
- dmax = conf.ipdynamic;
- otimer = 0;
- for (d = &ipdad[0], i = 0 ; i < dmax ; d++,i++ ) {
- if (d->timer == 0) {
- otimer = ipdadTimerMax;
- od = d;
- } else if (d->timer > otimer) {
- otimer = d->timer;
- od = d;
- }
- if (d->net == ddp.srcNet && d->node == ddp.srcNode)
- goto assign;
- }
- if (otimer <= ipdadTimerMin) {
- ig->op = -1;
- strcpy(ig->string, "no free address");
- return;
- }
- d = od;
- assign:
- d->net = ddp.srcNet;
- d->node = ddp.srcNode;
- d->timer = 1;
- ig->ipaddress = (d - &ipdad[0]) + conf.ipaddr + conf.ipstatic + 1;
- if (i == dmax) /* if this address may have been reassigned */
- arpdelete(ig->ipaddress);
- server:
- ig->string[0] = 0;
- ig->ipname = conf.ipname;
- ig->ipbroad = conf.ipbroad;
- ig->ipfile = conf.ipfile;
- bcopy((caddr_t)conf.ipother, (caddr_t)ig->ipother, sizeof ig->ipother);
- }
-
-
- short ipd_index, ipd_timer, ipd_first; /* 'static' */
-
- /*
- * Timeout unused ipdad table entries. Called once per second, sends
- * one 'tickle' per minute to each 'active' IP address client.
- * Sends at most one NBP per second.
- */
- ipdadtimer()
- {
- Entity ent;
- register struct ipdad *d;
-
- if (conf.ipdynamic == 0)
- return;
- /*
- * This one-time code runs between seconds 25 to 30 after the
- * gateway is booted. It does an nbplookup request for
- * all IPADDRESSes so we can initially fill in our table.
- */
- if (ipd_first < 30) {
- ipd_first++;
- if (ipd_first < 25) /* wait for RTMPs to establish */
- return;
- strcpy(ent.obj, "=");
- strcpy(ent.type, "IPADDRESS");
- strcpy(ent.zone, "*");
- nbplookup(&ent, 0, 0);
- return;
- }
- /*
- * This code runs every second after startup. Step thru
- * the table pinging active entries.
- */
- ipd_timer++;
- d = &ipdad[ipd_index];
- for ( ; ; d++, ipd_index++) {
- if (ipd_index >= conf.ipdynamic) {
- if (ipd_timer < 60)
- return;
- ipd_timer = ipd_index = 0;
- d = &ipdad[0];
- }
- /* dont ping empty or really old entries */
- if (d->timer == 0 || d->timer == ipdadTimerMax)
- continue;
- if (++d->timer > ipdadTimerMin)
- continue;
- iptoa(conf.ipaddr + conf.ipstatic + 1 + ipd_index, ent.obj);
- strcpy(ent.type, "IPADDRESS");
- strcpy(ent.zone, "*");
- nbplookup(&ent, d->net, d->node);
- ipd_index++;
- return;
- }
- }
-
-
- /*
- * Reply to ipdadtimer NBP 'tickle' received; reset timer.
- */
- ipdadreply(ifp, iaddr, daddr)
- struct ifnet *ifp;
- iaddr_t iaddr;
- register AddrBlock *daddr;
- {
- register struct ipdad *d;
- register i;
-
- i = iaddr - (conf.ipaddr + conf.ipstatic + 1);
- if (i < 0 || i >= conf.ipdynamic)
- return;
- d = &ipdad[i];
- d->timer = 1;
- d->net = daddr->net;
- d->node = daddr->node;
- }
-
-
- /*
- * Convert ASCII dot notation string 's' to long ip address.
- * 'n' is optional byte count.
- * Returns address, or 0 if error.
- */
- atoip(s, n)
- register char *s;
- {
- register addr, dots, num;
-
- dots = addr = num = 0;
- for ( ; ; s++, n--) {
- if (n == 0 || *s == '.' || *s == 0) {
- dots++;
- if (num > 255)
- return (0);
- addr = (addr << 8) + num;
- num = 0;
- if (n && *s == '.')
- continue;
- if (dots != 4)
- return (0);
- else
- return (addr);
- }
- if (*s >= '0' && *s <= '9')
- num = (num*10) + (*s - '0');
- else
- return (0);
- }
- }
-
-
- /*
- * Convert IP address to ASCII. Converts 'n' to string at 's'.
- * Returns number of bytes in s (minus null).
- */
- iptoa(n, s)
- register n;
- register char *s;
- {
- char buf[20];
- register char *cp;
- int i;
- register b;
-
- cp = buf;
- for (i = 0 ; i < 4 ; i++) {
- b = (n & 0xFF);
- n >>= 8;
- if (b) {
- while (b) {
- *cp++ = (b % 10) + '0';
- b /= 10;
- }
- } else {
- *cp++ = '0';
- }
- *cp++ = '.';
- }
- cp -= 2; /* skip last dot */
- i = 0;
- while (cp >= buf) {
- *s++ = *cp--;
- i++;
- }
- *s = 0;
- return (i);
- }
-
-
- /*
- * Setup the standard IP header fields for a destination
- */
- setiphdr(p, dst)
- struct pbuf *p;
- iaddr_t dst;
- {
- register struct ip *ip = (struct ip *)p->p_off;
-
- ip->ip_v = IPVERSION;
- ip->ip_hl = sizeof(*ip) >> 2;
- ip->ip_tos = 0;
- ip->ip_len = p->p_len;
- ip->ip_id = ipid++;
- ip->ip_off = 0;
- ip->ip_ttl = IPFRAGTTL;
- ip->ip_p = IPPROTO_UDP;
- ip->ip_src = conf.ipaddr;
- ip->ip_dst = dst;
- ip->ip_sum = 0;
- ip->ip_sum = in_cksum((caddr_t)ip, sizeof(*ip));
- }
-
-
- /*
- * assumes ddp.type already set and that the reply goes to the node specified
- * by: (ddp.srcNet, ddp.srcNode, ddp.srcSkt)
- *
- * p should be aligned so offset points to start of lap data with room
- * for lap + long ddp. p->p_len should record the correct length
- *
- * skt is outgoing socket
- *
- */
- ddpreply(p, skt)
- register struct pbuf *p;
- int skt;
- {
- u_char dst;
- register struct DDP *dp = &ddp;
-
- dp->length = p->p_len - lapSize;
- dp->checksum = 0;
- dp->dstNet = dp->srcNet;
- dp->dstNode = dp->srcNode;
- dp->dstSkt = dp->srcSkt;
- dp->srcNet = source_if->if_dnet;
- dp->srcNode = source_if->if_dnode;
- dp->srcSkt = skt;
- bcopy((caddr_t)dp, p->p_off+lapSize, ddpSize);
- routeddp(p, 0, 0);
- }
-